package com.xiaojie.edi.mybatisplus.sql;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.google.common.base.CaseFormat;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.xiaojie.context.DataInfoContext;
import com.xiaojie.edi.mybatisplus.FieldTypeHandleService;
import com.xiaojie.edi.mybatisplus.listener.DataEDIApplicationRunner;
import com.xiaojie.importdata.CreateInsertSql;
import com.xiaojie.parse.model.DataModel;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author wangye
 * @classname MybatisPlusCreateInsertSql
 * @date 2020/10/10 13:32
 **/
@Component
public class EDIMybatisPlusCreateInsertSql implements CreateInsertSql {

    @Autowired
    private FieldTypeHandleService fieldTypeHandleService;

    @Override
    public List<String> createInsertSql(Map<String, List<Map>> dataMap, List<String> tableNameList) throws ClassNotFoundException {
        List<String> insertSqlList = Lists.newArrayListWithCapacity(tableNameList.size());
        for (String tableName : tableNameList) {
            // 获取表名对应的反射类名
            TableInfo tableInfoFormMybatis = DataEDIApplicationRunner.TABLE_INFO_MAP.get(tableName);
            String insertSql;
            if (tableInfoFormMybatis != null) {
                Class<?> clazz = tableInfoFormMybatis.getEntityType();
                // 获取mybatis_plus表信息
                TableInfo tableInfo = TableInfoHelper.getTableInfo(clazz);
                insertSql = getBatchInsertSql(tableInfo, clazz, dataMap.get(tableName));
            } else {
                insertSql = getMultiInsertSqlByData(tableName, dataMap.get(tableName));
            }
            if (insertSql != null)
                insertSqlList.add(insertSql);
        }
        return insertSqlList;
    }


    /**
     * 根据每条数据生成独立的insert语句
     *
     * @param tableName
     * @param maps
     * @Date: 2024/4/3 11:10
     * @return:
     **/
    private  String getMultiInsertSqlByData(String tableName, List<Map> maps) {

        if (CollectionUtil.isEmpty(maps)) {
            return null;
        }

        return maps.stream().map(value -> {

            StringBuilder insertSql = new StringBuilder("INSERT INTO ").append(tableName).append(" (");
            StringBuilder columns = new StringBuilder();
            StringBuilder valueBuilder = new StringBuilder();
            value.forEach(
                    (k, v) -> {
                        if (v != null) {
                            columns.append("`").append(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, k.toString())).append("`,");
                            valueBuilder.append(fieldTypeHandleService.importHandleDataByFieldType(v, null)).append(",");
                        }
                    });
            if (columns.length() == 0) {
                return null;
            }
            return insertSql
                    .append(columns.substring(0, columns.lastIndexOf(","))).append(") values (")
                    .append(valueBuilder.substring(0, valueBuilder.lastIndexOf(","))).append(");");

        }).filter(Objects::nonNull).reduce((a, b) -> a.append(b)).get().toString();
    }



    private  String getBatchInsertSqlByData(String tableName, List<Map> maps) {
        String batchInsertSql = "INSERT INTO %s (%s) %s";

        StringBuilder insertColumnBuilder = new StringBuilder();
        List<String> filedNames = new ArrayList<>();

        if (CollUtil.isEmpty(maps)) {
            return null;
        }

        //1.记录 字段名 及 顺序
        maps.get(0).keySet().forEach(
                k -> {
                    filedNames.add(k.toString());
                    insertColumnBuilder.append("`").append(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, k.toString())).append("`,");
                }
        );
        // 表名多了,删除最后一个,
        if (insertColumnBuilder.charAt(insertColumnBuilder.length() - 1) == ',') {
            insertColumnBuilder.deleteCharAt(insertColumnBuilder.length() - 1);
        }

        //数据
        List<String> valueStrList = Lists.newArrayListWithCapacity(maps.size());
        maps.forEach(
                v -> {
                    StringBuilder sb = new StringBuilder();
                    sb.append("(");
                    for (int i = 0; i < filedNames.size(); i++) {
                        String name = filedNames.get(i);
                        sb.append(fieldTypeHandleService.importHandleDataByFieldType(v.get(name), null));
                        if (i < filedNames.size() - 1) {
                            sb.append(",");
                        }
                    }
                    sb.append(")");
                    valueStrList.add(sb.toString());
                }
        );
        String valueStr = " values " + StringUtils.join(valueStrList, ",") + ";";

        // 执行sql
        return String.format(batchInsertSql, tableName, insertColumnBuilder, valueStr);
    }

    private String getBatchInsertSql(TableInfo tableInfo, Class<?> modelClass, List<Map> dataList) {
        //表名 + 字段类型map
        String tableName = tableInfo.getTableName();
        Map<String, Class> fieldClassTypeMap = tableInfo.getFieldList().stream()
                .collect(Collectors.toMap(
                        TableFieldInfo::getColumn, TableFieldInfo::getPropertyType)
                );

        String batchInsertSql = "INSERT INTO %s (%s) %s";
        StringBuilder insertColumnBuilder = new StringBuilder();
        Field[] fields = modelClass.getDeclaredFields();

        if (CollectionUtil.isEmpty(dataList))
            return null;

        // valueList = list<list>
        List<List<Object>> valueList = Lists.newArrayListWithCapacity(dataList.size());
        for (int i = 0; i < dataList.size(); i++) {
            valueList.add(Lists.newArrayList());
        }

        //添加column
        for (int i = 0, len = fields.length; i < len; i++) {
            Field field = fields[i];
            //过滤静态变量
            if (Modifier.isStatic(field.getModifiers())) {
                continue;
            }
            // 只导入 含有@TableField注解 的字段 = 导出时候有的数据
            //过滤注解说明非持久化列
            TableField annotation = field.getAnnotation(TableField.class);
            if (annotation != null && !annotation.exist()) {
                continue;
            }
            String fieldName = field.getName();
            //1.1 一句sql 拼接 字段名
            // 字段名 「驼峰式」转「下划线式」 = 数据库字段名
            insertColumnBuilder.append("`").append(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, fieldName)).append("`,");

            //1.2.1 一句sql 准备数据list
            for (int j = 0; j < dataList.size(); j++) {
                List values = valueList.get(j);
                values = values == null ? Lists.newArrayList() : values;

                // 获取json数据里的字段名
                fieldName = convertFieldName(fieldName);

                //获取字段值
                Object value = dataList.get(j).get(fieldName);
                value = fieldTypeHandleService.importHandleDataByFieldType(value, fieldClassTypeMap.get(fieldName));
                values.add(value);
            }
        }

        // 1.2 一句sql 拼接 数据
        List<String> valueStrList = Lists.newArrayListWithCapacity(valueList.size());
        for (List<Object> list : valueList) {
            StringBuilder s = new StringBuilder("(")
                    .append(StringUtils.join(list, ",")).append(")");
            valueStrList.add(s.toString());
        }

        String valueStr = " values " + StringUtils.join(valueStrList, ",") + ";";

        // 多了,删除最后一个,
        if (insertColumnBuilder.charAt(insertColumnBuilder.length() - 1) == ',') {
            insertColumnBuilder.deleteCharAt(insertColumnBuilder.length() - 1);
        }
        // 执行sql
        return String.format(batchInsertSql, tableName, insertColumnBuilder, valueStr);
    }

    private String convertFieldName(String fieldName) {
        DataModel dataModel = DataInfoContext.get().getDataModelInfo();

        if (!dataModel.getSettings().getFieldNameIsCamelCase()) {
            return CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, fieldName);
        }
        return fieldName;
    }

}
